﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Media3D;


namespace LxCFD
{
    public class PossionEquation : PossionEquationBase
    {
        public List<BoundaryFixValue> FixValueBounds = new List<BoundaryFixValue>();
        public List<BoundaryFixFlux> FixFluxBounds = new List<BoundaryFixFlux>();
        public List<BoundaryFixhT> FixhTBounds = new List<BoundaryFixhT>();
        public List<BoundaryHeadBase> CoupledBounds = new List<BoundaryHeadBase>();

        public void SetZone_CommonTerm(Value1Base<double> gamma, ValueBase<double> source, Value1Base<double> iniValue, double relaxFactor)
        {
            clear_eFlags();
            FixValueBounds.Clear();
            FixFluxBounds.Clear();
            FixhTBounds.Clear();
            CoupledBounds.Clear();

            this.Gamma = gamma;
            this.Source = source;
            this.IniValue = iniValue;
            this.RelaxFactor = relaxFactor;
        }
        public void SetBoundary_FixValue(Value1Base<double> fixValue, FvThread thread)
        {
            BoundaryFixValue boundaryFixValue = new BoundaryFixValue();
            boundaryFixValue.SetHead(thread);
            boundaryFixValue.SetFixValue(fixValue);

            FixValueBounds.Add(boundaryFixValue);
            e_FixValue.Add(thread.ID);
        }
        public void SetBoundary_FixFlux(Value1Base<double> fixFlux, FvThread thread)
        {
            BoundaryFixFlux boundaryFixFlux = new BoundaryFixFlux();
            boundaryFixFlux.SetHead(thread);
            boundaryFixFlux.SetFixFlux(fixFlux);

            FixFluxBounds.Add(boundaryFixFlux);
            e_ALUO0.Add(thread.ID);
        }
        public void SetBoundary_FixCoupledhT(Value1Base<double> fixh, Value1Base<double> fixT, FvThread thread)
        {
            BoundaryFixhT boundaryFixhT = new BoundaryFixhT();
            boundaryFixhT.SetHead(thread);
            boundaryFixhT.SetFixhT(fixh, fixT);

            FixhTBounds.Add(boundaryFixhT);
            e_ALUO0.Add(thread.ID);
        }
        public void SetBound_Coupled(FvThread thread)
        {
            var coupledBound = new BoundaryHeadBase();
            coupledBound.SetHead(thread);

            CoupledBounds.Add(coupledBound);
            e_Couple.Add(thread.ID);
        }

        public override void Initialize()
        {
            MultiThreads.RunCalTasks(initialize);
        }
        public void initialize(int taskIndex)
        {
            set_x(IniValue, InnerIndex, taskIndex);
            Set_x_Bound(taskIndex);
            foreach (BoundaryFixFlux b in FixFluxBounds)
            {
                set_x(IniValue, b.ThreadIndex, taskIndex);
            }
            foreach (BoundaryFixhT b in FixhTBounds)
            {
                set_x(IniValue, b.ThreadIndex, taskIndex);
            }
            foreach (var b in CoupledBounds)
            {
                set_x(IniValue, b.ThreadIndex, taskIndex);
            }
        }
        public override void Set_x_Bound(int taskIndex)
        {
            foreach (BoundaryFixValue b in FixValueBounds)
            {
                if (b.BoundxState.GetIsNeedToCal(taskIndex))
                {
                    set_x(b.FixValue, b.ThreadIndex, taskIndex);
                }
            }
        }
        public override void SetAb_Step1(int taskIndex)
        {
            setAb_step1_inner(taskIndex);
            foreach (BoundaryFixValue b in FixValueBounds)
            {
                setAb_step1_bound(b.ThreadIndex, taskIndex);
            }
            foreach (BoundaryFixFlux b in FixFluxBounds)
            {
                if (b.FixFlux.IsEqual0())
                {
                    setBound_flux0(b.ThreadIndex, taskIndex);
                }
                else
                {
                    setBound_flux(b.ThreadIndex, b.FixFlux, taskIndex);
                }
            }
            foreach (BoundaryFixhT b in FixhTBounds)
            {
                setBound_fixhFixT(b.ThreadIndex, b.Fixh, b.FixT, taskIndex);
            }
        }
        public override void SetAb_Step2(int taskIndex)
        {
            if (Source is Value1Base<double> source1)
            {
                setAb_step2(source1, taskIndex);
            }
            else if (Source is Value2Base<double> source2)
            {
                setAb_step2(source2, taskIndex);
            }
            else
            {
                LxConsole.Error("未知的源项类型");
            }
        }
        public override void Update_x_Bound(int taskIndex)
        {
            foreach (BoundaryFixFlux b in FixFluxBounds)
            {
                if (b.FixFlux.IsEqual0())
                {
                    updateBound_grad0(b.ThreadIndex, taskIndex);
                }
                else
                {
                    updateBound_flux(b.ThreadIndex, taskIndex);
                }
            }
            foreach (BoundaryFixhT b in FixhTBounds)
            {
                updateBound_fixhFixT(b.ThreadIndex, taskIndex);
            }
        }

        public class BoundaryFixValue : BoundaryHeadBase
        {
            public Value1Base<double> FixValue;
            public ValueStateLog BoundxState;
            public void SetFixValue(Value1Base<double> fixValue)
            {
                this.FixValue = fixValue;
                BoundxState = new ValueStateLog(fixValue.IsConstant());
            }
        }
        public class BoundaryFixFlux : BoundaryHeadBase
        {
            public Value1Base<double> FixFlux;
            public void SetFixFlux(Value1Base<double> fixFlux)
            {
                this.FixFlux = fixFlux;
            }
            //cell的数据中已设置边界的volumn等于边界面的面积
        }
        public class BoundaryFixhT : BoundaryHeadBase
        {
            public Value1Base<double> Fixh;
            public Value1Base<double> FixT;
            public void SetFixhT(Value1Base<double> fixh, Value1Base<double> fixT)
            {
                this.Fixh = fixh;
                this.FixT = fixT;
            }
        }
    }
}
